package com.demo.search.service.impl;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.xmlparser.CorePlusExtensionsParser;
import org.apache.lucene.xmlparser.QueryTemplateManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import com.demo.common.StringUtils;
import com.demo.search.engine.HighlighterHandler;
import com.demo.search.engine.SearchEngine;
import com.demo.search.engine.annotation.HighlighterHandlerImpl;
import com.demo.search.service.BaseXmlQueryService;
import com.demo.search.support.PageResultSupport;
import com.demo.search.util.LuceneUtils;

/**
 * 基于xml查询的服务默认实现
 * 
 * @author ryuu.kk  at 2013-05-14
 * @since 
 */
public class BaseXmlQueryServiceImpl implements BaseXmlQueryService, InitializingBean{

	/**
	 * 检索模板名称key
	 */
	public static final String QUERY_TYPE = "_template";
	
	/**
	 * 内容最大长度,高于这个长度将被截取
	 */
	public static final int MAX_LENGTH = 220;
	
	/**
	 * Lucene's IndexWriter关键key
	 */
	public static final String LUCENE_INDEX_WRITER = "Lucene.IndexWriter";
	
	/**
	 * 查询模板管理器,将xsl文件转化为查询模板
	 */
	private QueryTemplateManager queryTemplateManager;
	
	/**
	 * Lucene的Core包扩展xml表达式分析器
	 * 允许自定义xml标签;以后将扩展该对象
	 */
	private CorePlusExtensionsParser xmlParser;
	
	/**
	 * 索引查询器
	 */
	private IndexSearcher searcher;
	
	/**
	 * 索引写入对象
	 */
	private IndexWriter indexWriter;
	
	/**
	 * 内容最大长度,高于这个长度将被截取
	 */
	private int maxLength = MAX_LENGTH;
	
	// 使用Lucene3.6版本的分析器
	//private Analyzer analyzer = new StandardAnalyzer(org.apache.lucene.util.Version.LUCENE_36);
	private Analyzer analyzer = LuceneUtils.createChineseAnalyzer();
	
	/**
	 * 检索引擎
	 */
	private SearchEngine searchEngine;
	
	@Override
	public <T> PageResultSupport<T> queryList(String templateName, Map<String, Object> params, Class<T> clazz, int firstResult, int maxResult) {
		
		//分页结果的总数量  
		int total = 0;
		PageResultSupport<T> pageResults = null;
		Properties completedFormFields = new Properties();
		Set<String> keySet = params.keySet();
		for (String key : keySet) {
			Object obj = params.get(key);
			String value = "";
			if (obj != null) {
				value = obj.toString();
			}
			if ((value != null) && (value.trim().length() > 0)) {
				completedFormFields.setProperty(key, value.trim());
			}
		}
		
		org.w3c.dom.Document xmlQuery = null;
		try {
			if (StringUtils.isEmpty(templateName)) {
				// 空模板名称,则使用默认模板
				xmlQuery = queryTemplateManager.getQueryAsDOM(completedFormFields);
			} else {
				// Create an XML query by populating template with given user
				xmlQuery = queryTemplateManager.getQueryAsDOM(completedFormFields, templateName);
			}

			// Parse the XML to produce a Lucene query
			Query query = xmlParser.getQuery(xmlQuery.getDocumentElement());
			
			//分页查询
            TopScoreDocCollector topCollector = TopScoreDocCollector.create(firstResult + maxResult, false);
			// Run the query
			searcher.search(query, topCollector);
			
            total = topCollector.getTotalHits();  
            ScoreDoc[] scoreDocs = topCollector.topDocs(firstResult, maxResult).scoreDocs;
			if (scoreDocs != null) {
				Document[] results = new Document[scoreDocs.length];
				for (int i = 0; i < results.length; i++) {
					results[i] = searcher.doc(scoreDocs[i].doc);
				}
				//searchEngine.documentToTarget(results, clazz);
				
				List<T> resultList = searchEngine.documentToTarget(Arrays.asList(results), clazz, maxLength);
				pageResults = new PageResultSupportImpl<T>(resultList, total);
				return pageResults;
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public <T> PageResultSupport<T> queryList(String templateName,
			Map<String, Object> params, Class<T> clazz, int firstResult, int maxResult,
			String[] preColorTags, String[] postColorTags) {
		
		//分页结果的总数量  
		int total = 0;
		PageResultSupport<T> pageResults = null;
		Properties completedFormFields = new Properties();
		Set<String> keySet = params.keySet();
		for (String key : keySet) {
			Object obj = params.get(key);
			String value = "";
			if (obj != null) {
				value = obj.toString();
			}
			if ((value != null) && (value.trim().length() > 0)) {
				completedFormFields.setProperty(key, value.trim());
			}
		}
		
		org.w3c.dom.Document xmlQuery = null;
		try {
			if (StringUtils.isEmpty(templateName)) {
				// 空模板名称,则使用默认模板
				xmlQuery = queryTemplateManager.getQueryAsDOM(completedFormFields);
			} else {
				// Create an XML query by populating template with given user
				xmlQuery = queryTemplateManager.getQueryAsDOM(completedFormFields, templateName);
			}

			// Parse the XML to produce a Lucene query
			Query query = xmlParser.getQuery(xmlQuery.getDocumentElement());

			//分页查询
            TopScoreDocCollector topCollector = TopScoreDocCollector.create(firstResult + maxResult, false);
            
            // 打开索引,得到近实时索引
            openIndex(this.indexWriter);
			// Run the query
			searcher.search(query, topCollector);
			
            total = topCollector.getTotalHits();  
            ScoreDoc[] scoreDocs = topCollector.topDocs(firstResult, maxResult).scoreDocs;
			if (scoreDocs != null) {
				Document[] results = new Document[scoreDocs.length];
				for (int docID = 0; docID < results.length; docID++) {
					results[docID] = searcher.doc(scoreDocs[docID].doc);
					// TokenStream contentTokenStream = analyzer.tokenStream("content", new StringReader(result));
					// TokenStream contentTokenStream = TokenSources.getAnyTokenStream(searcher.getIndexReader(), docID, "contents", analyzer);
				}
				//searchEngine.documentToTarget(results, clazz);
				// 获得高亮处理对象
				HighlighterHandler highlighterHandler = new HighlighterHandlerImpl(analyzer, query, searcher.getIndexReader(), preColorTags, postColorTags);
				List<T> resultList = searchEngine.documentToTarget(Arrays.asList(results), clazz, highlighterHandler, maxLength);
				pageResults = new PageResultSupportImpl<T>(resultList, total);
				return pageResults;
			}
			
			/* *************************************************
			// Run the query
			TopDocs topDocs = searcher.search(query, 10);
			if (topDocs != null) {
				ScoreDoc[] sd = topDocs.scoreDocs;
				Document[] results = new Document[sd.length];
				
				//searchEngine.documentToTarget(results, clazz);
				for (int i = 0; i < results.length; i++) {
					results[i] = searcher.doc(sd[i].doc);
				}
				List<T> resultList = searchEngine.documentToTarget(Arrays.asList(results), clazz);
				pageResults = new PageResultSupportImpl<T>(resultList, Float.floatToRawIntBits(topDocs.getMaxScore()));
				return pageResults;
			}**************************************************** */
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		Assert.notNull(this.analyzer);
		Assert.notNull(this.xmlParser);
		Assert.notNull(this.searchEngine);
		Assert.notNull(this.queryTemplateManager);
		// 打开索引
		openIndex(this.indexWriter);
	}

	/**
	 * 获得Lucene的索引(近实时速印)
	 * @param config ServletConfig
	 * @throws CorruptIndexException
	 * @throws IOException
	 */
	protected void openIndex(IndexWriter writer) throws CorruptIndexException, IOException {
		// 获得一个近实时索引(a near real time IndexReader)
		IndexReader indexReader = IndexReader.open(writer, true);
		
		// 索引快照
		IndexReader newReader = IndexReader.openIfChanged(indexReader);
		if (newReader != null) {
			indexReader.close();
			indexReader = newReader;
		}
		this.searcher = new IndexSearcher(indexReader);
	}
	
	public void setIndexWriter(IndexWriter indexWriter) {
		this.indexWriter = indexWriter;
	}

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
	}

	public void setXmlParser(CorePlusExtensionsParser xmlParser) {
		this.xmlParser = xmlParser;
	}

	public void setSearchEngine(SearchEngine searchEngine) {
		this.searchEngine = searchEngine;
	}
	
	public void setQueryTemplateManager(QueryTemplateManager queryTemplateManager) {
		this.queryTemplateManager = queryTemplateManager;
	}
	
	
	public void setMaxLength(int maxLength) {
		this.maxLength = maxLength;
	}

	/**
	 * 全文检索的分页结果对象
	 * 
	 * @author ryuu.kk  at 2013-05-15 19:44 
	 * @param <T> 结果对象
	 */
	private class PageResultSupportImpl<T> extends com.demo.search.support.PageResultSupport<T> {

		/**
		 * 版本序列化ID
		 */
		private static final long serialVersionUID = -2224348737847883829L;

		/**
		 * 构造函数
		 * 构造检索结果容器对象
		 * @param results 结果对象
		 * @param totalResults 整个检索集合的条数(总条数)
		 */
		public PageResultSupportImpl(Collection<T> results, int totalResults) {
			this.results = results;
			this.totalResults = totalResults;
		}
		
		/**
		 * 结果集合
		 */
		private final Collection<T> results;
		
		/**
		 * 总共得到结果条数
		 */
		private final int totalResults;
		
		@Override
		public Iterator<T> iterator() {
			return results.iterator();
		}

		@Override
		public int size() {
			return results.size();
		}

		@Override
		public Collection<T> getResults() {
			return results;
		}
		@Override
		public int getTotalResults() {
			return totalResults;
		}
	}
}
